/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.javanile.me.chessengine;

/**
 *
 * @author cicciodarkast
 */
public class Node {
	
    private char[]	b;	// Board 
    private int		t;	// Turn
    private int		s;	// Focussed square on square loop
	private char	p;	// Piece in focussed square (aka fsp)
	private int		a;	// Ability cursor for long piece
	private int		k;	// kind of move
	private char	c;	// captured piece
	private char	w;	// promoted piece
	private int		h;
	private int		d;
	private int		n;
    private int		o;
	private int		j;
	private int		e;	// en-passant
	private boolean	l;
	private int		g;	// Castling
	private boolean	x;	// a king is under chck
            
    public Node() {      
        this(Constants.START_POSITION);
    }
	
    public Node(String fen) {
        this.parse_fen(fen);
    }
    
	public boolean testSquare() {
		return b[s]!='.';
	}
	
	public boolean testPiece() {
		return Constants.MAP[p+Constants.COLOR]==t;
	}
	
	public boolean testPawn() {
		return Constants.MAP[p+Constants.ISPAWN]==1;
	}
	
	public boolean testPawnSimple() {
		k = Constants.MK_PAWN_SIMPLE;
		o = s - Constants.MAP[p+Constants.COLOR] * 12;
		c = '.';
		return b[o]=='.';
	}
	
	public boolean testPawnEstCapture() {
		o = s - Constants.MAP[p+Constants.COLOR] * 11;	
		c = b[o];
		return (-Constants.MAP[p+Constants.COLOR])==Constants.MAP[b[o]+Constants.COLOR];
	}
	
	public boolean testPawnWestCapture() {
		o = s - Constants.MAP[p+Constants.COLOR] * 13;		
		c = b[o];
		return (-Constants.MAP[p+Constants.COLOR])==Constants.MAP[b[o]+Constants.COLOR];
	}
	
	public boolean testPawnDouble() {
		if (s/12==Constants.MAP[t+Constants.PAWNDOUBLE]) {
			o = s - Constants.MAP[p+Constants.COLOR] * 24;
			j = s - Constants.MAP[p+Constants.COLOR] * 12;		
			c = '.';
			k = Constants.MK_PAWN_DOUBLE;
			return (b[o]=='.')&&(b[j]=='.');
		}
		return false;
	}
	
	public boolean testPawnEnpassant() {
		if (e>0) {
			k = Constants.MK_PAWN_ENPASSANT;
			o = s - Constants.MAP[p+Constants.COLOR] * 13;			
			c = b[s-Constants.MAP[p+Constants.COLOR]];
			if (o == e) {
				return true;
			}
			o = s - Constants.MAP[p+Constants.COLOR] * 11;		
			c = b[s+Constants.MAP[p+Constants.COLOR]];
			if (o == e) {
				return true;
			}
		}
		c = '.';
		return false;
	}
	
	public boolean testPromotion() {
		return (t==-1) ? o/12==9 : o/12==2;
	}
	
	public boolean testLongPiece() {
		return Constants.MAP[p+Constants.ISLONG]==1;
	}
	
	public boolean testHopePiece() {
		return Constants.MAP[p+Constants.ISLONG]==2;
	}
	
	public boolean testHope() {
		k = Constants.MK_SIMPLE;
		return (b[o]=='.')||(-t==Constants.MAP[b[o]+Constants.COLOR]);
	}
		
	public boolean testCastling() {		
		if (p=='K') {
			return ((g&1)==1)||((g&2)==2);	
		}
		if (p=='k') {
			return ((g&4)==4)||((g&8)==8);			
		}
		return false;
	}
	
	public boolean testShortCastling() {
		o = s + 2;	
		k = Constants.MK_SHORT_CASTLING;		
		return (b[s+1]=='.')&&(b[s+2]=='.');
	}
	
	public boolean testLongCastling() {
		o = s - 2;			
		k = Constants.MK_LONG_CASTLING;
		return (b[s-1]=='.')&&(b[s-2]=='.')&&(b[s-3]=='.');
	}
	
	public boolean nextAbility() {
		a++;
		n = Constants.MAP[p+Constants.ABILITY];
		h = Constants.MAP[p+Constants.STARTABILITY];
		d =	Constants.MAP[h+a];
		o = s;
		l = true;		
		//System.out.println(" - "+a+" "+d);
		return a<n;
	}
	
	public boolean nextLong() {
		o+=d;
		//System.out.println("   - "+s+" "+o);
		return l;
	}	
	
	public boolean testLong() {
		l = b[o]=='.';
		c = b[o];
		k = Constants.MK_SIMPLE;
		return (b[o]=='.')||(-t==Constants.MAP[b[o]+Constants.COLOR]);
	}
	
	public boolean nextHope() {
		a++;
		h = Constants.MAP[p+Constants.STARTABILITY];
		d = Constants.MAP[h+a];
		o = s + d;
		c = b[o];
		//System.out.println("   - "+s+" "+o);
		return a<8;
	}
	
	public Move getMove() {		
		return new Move(p,s,o,c,k,e,g,w);
	}
	
	public Piece getPiece() {
		return new Piece(p);
	}
	
	public String getAbilityInfo() {
		return "("+a+","+n+","+h+","+d+")";
	}
	
	public String getLongInfo() {
		return "("+Square.toString(o)+")";
	}
	
	public String getHopeInfo() {
		return "("+a+","+n+","+h+","+d+" "+Square.toString(o)+")";
	}
	
	public void set(Node node) {
		t = node.getTurn();
		char[] temp = node.getCharBoard();
		for(int i1=0;i1<12;i1++) {
			for(int i2=0;i2<12;i2++) {
				b[i2*12+i1] = temp[i2*12+i1];
			}
		}            
    }
	
	public void setQueenPromotion() {
		w = (t==1) ? 'Q' : 'q';
	}
	
	public void setRookPromotion() {
		w = (t==1) ? 'R' : 'r';
	}
	
	public void setBishopPromotion() {
		w = (t==1) ? 'B' : 'b';
	}
	
	public void setKnightPromotion() {
		w = (t==1) ? 'N' : 'n';
	}
	
	public void setNotPromotion() {
		w = 0;
	}
	
    public void setFocusSquare(int square) {
		s = square;
		p = b[s];
		a = -1;
    }
    	
    public void doMove(Move m) {
		e = 0;                
        switch(m.getKind()) {
            case Constants.MK_SHORT_CASTLING:
                g = (t==1) ? g&~3 : g&~12;
				setBoard(m.getTo(), getPieceAt(m.getFrom()));
                setBoard(m.getTo()-1, getPieceAt(m.getFrom()+3));
                setBoard(m.getFrom(), '.');
				setBoard(m.getFrom()+3, '.');
				break;
            case Constants.MK_LONG_CASTLING:
				g = (t==1) ? g&~3 : g&~12;
				setBoard(m.getTo(), getPieceAt(m.getFrom()));
                setBoard(m.getTo()+1, getPieceAt(m.getFrom()-4));
                setBoard(m.getFrom(), '.');
				setBoard(m.getFrom()-4, '.');
				break;
            case Constants.MK_PAWN_DOUBLE:	
				setBoard(m.getTo(), getPieceAt(m.getFrom()));
                setBoard(m.getFrom(), '.');
                e = getEnpassantSquare(m.getFrom());
				break;
			case Constants.MK_PAWN_ENPASSANT:	
				setBoard(m.getTo(), getPieceAt(m.getFrom()));                
				setBoard(m.getFrom(), '.');
				setBoard(getEnpassantSquare(m.getTo()), '.');                
				break;
			case Constants.MK_SIMPLE:
			default:
                setBoard(m.getTo(), getPieceAt(m.getFrom()));
                setBoard(m.getFrom(), '.');
			    break;
        }
        changeTurn();        
    }
    public void unMove(Move m) {
		e = m.getEnpassantStatus();
		g = m.getCastlingStatus();
		switch(m.getKind()) {
            case Constants.MK_SHORT_CASTLING:
                //if (t==-1) {g[0]=1;g[1]=1;g[2]=1;g[3]=1;}
				//if (t== 1) {g[4]=1;g[5]=1;g[6]=1;g[7]=1;}
				setBoard(m.getTo(), '.');
                setBoard(m.getFrom(), m.getPiece());
				setBoard(m.getFrom()+3, getPieceAt(m.getFrom()+1));	
				setBoard(m.getFrom()+1, '.');
				break;
            case Constants.MK_LONG_CASTLING:
				//if (t==-1) {g[0]=1;g[1]=1;g[2]=1;g[3]=1;}
				//if (t== 1) {g[4]=1;g[5]=1;g[6]=1;g[7]=1;}
				setBoard(m.getTo(), '.');
                setBoard(m.getFrom(), m.getPiece());
				setBoard(m.getFrom()-4, getPieceAt(m.getFrom()-1));
				setBoard(m.getFrom()-1, '.');
				break;
            case Constants.MK_PAWN_ENPASSANT:	
				setBoard(getEnpassantSquare(m.getTo()), m.getCaptured());
				setBoard(m.getTo(),'.');
                setBoard(m.getFrom(), m.getPiece());
				e = m.getTo();
                break;
			case Constants.MK_SIMPLE:
			default:
                setBoard(m.getTo(), m.getCaptured());
                setBoard(m.getFrom(), m.getPiece());
                break;
        }
        changeTurn();        
    }
    
	public void setBoard(int s,char p) {
        b[s] = p;        
    }
    public void setBoard(Square s,char p) {
        b[(s.getRank()+2)*12+s.getFile()+2] = p;        
    }
	
	public int getEnpassantSquare(int from) {
		return from>72 ? from-12 : from+12;
	}
	
    public Board getBoard() {
        return new Board(b);        
    }
	public char[] getCharBoard() {
		return b;
	}
    
	public char getBoard(int r, int f) {
        return b[(r+2)*12+f+2];        
    }
	public Piece getPiece(Square s) {
		return new Piece(b[(s.getRank()+2)*12+s.getFile()+2]);
	}
	
    public boolean isWhiteTurn() {
        return t==1;
    }
    public boolean isBlackTurn() {
        return t==-1;
    }
	private void changeTurn() {
        t = -t;
    }
	public int getTurn() {
        return t;
    }
	
	public char getPieceAt(int square) {
		return b[square];
	}
	
	public boolean testKings() {
		boolean wk=false,bk=false;
		for(int i=0;i<b.length;i++) {
			if (b[i]=='k') bk = true;
			if (b[i]=='K') wk = true;
		}
		return wk&&bk;
	}
	
    /*
	public boolean isWhiteLongPiece() {
		char p = getBoard(focus_square);
		return (p=='B')||(p=='R')||(p=='Q');
	}
    public boolean isBlackLongPiece() {
		char p = getBoard(focus_square);
		return (p=='b')||(p=='r')||(p=='q');
	}
    public boolean isWhiteSquare() {		
        return getPieceColor(focus_square) == 1;
    }
    public boolean isBlackSquare() {
        return getPieceColor(focus_square) == -1;
    }
    public boolean isBlackPawn() {
        return getBoard(focus_square)=='p';
    }
    public boolean isWhitePawn() {
        return getBoard(focus_square)=='P';
    }
    public boolean isBlackPawnRank() {
        return focus_square.getRank()==1;
    }
    public boolean isWhitePawnRank() {
        return focus_square.getRank()==6;
    }
	public boolean isFileH() {
		return focus_square.getFile()==7;
	}
	public boolean isFileA() {
		return focus_square.getFile()==0;
	}
			
  
    
    public Move getMove(Square from, Square to) {
        return new Move(getBoard(from),from,to,getBoard(to),Constants.MK_SIMPLE);
    }
    public Move getMove(int mk) {
        Square from = focus_square;
        Square to = from.shift(Constants.DELTA(getBoard(from), mk));
       return new Move(getBoard(from),from,to,getBoard(to),mk);
		//return new Move("e2e4");
    }    
    public Move getMove(Square to, int mk) {
        Square from = focus_square;
        return new Move(getBoard(from),from,to,getBoard(to),mk);
    }    
	
	public Move getWhitePawnDoubleMove() {
		return getMove(Constants.MK_WPD);
	}
	public Move getWhitePawnEstCaptureMove() {
		return getMove(Constants.MK_WPCE);
	}
    public Move getWhitePawnWestCaptureMove() {
		return getMove(Constants.MK_WPCW);
	}
    public Move getWhitePawnSimpleMove() {
		return getMove(Constants.MK_WPS);
	}
    public Move getBlackPawnSimpleMove() {
		return getMove(Constants.MK_BPS);
	}
	public Move getBlackPawnDoubleMove() {
		return getMove(Constants.MK_BPD);
	}	
	public Move getBlackPawnEstCaptureMove() {
		return getMove(Constants.MK_BPCE);
	}
    public Move getBlackPawnWestCaptureMove() {
		return getMove(Constants.MK_BPCW);
	}
    public boolean isFreeOrOpponentSquare(Square s) {
        char p = getBoard(s);
        if (t == -1) {
			if ((p=='.')||(p=='P')||(p=='N')||(p=='B')||(p=='R')||(p=='Q')||(p=='K')) return true;		    
        } else {
			if ((p=='.')||(p=='p')||(p=='n')||(p=='b')||(p=='r')||(p=='q')||(p=='k')) return true;		
        }
        return false;
    }
    public boolean haveOpponentPieceIn(Square to) {
		if (getBoard(to)!='.') {
			return (getPieceColor(focus_square)!=getPieceColor(to));
		}
		return false;
	}
	public int getPieceColor(Square s) {
		char p = getBoard(s);
		if ((p=='p')||(p=='n')||(p=='b')||(p=='r')||(p=='q')||(p=='k')) return -1;
		if ((p=='P')||(p=='N')||(p=='B')||(p=='R')||(p=='Q')||(p=='K')) return  1;
		return 0;
	}
	public boolean isFreeSquare(Square s) {
		return getBoard(s)=='.';
	}
	 * 
	 */
    private void parse_fen(String fen) {
		
		t = 1;
        b = new char[144];
		g = 0;
        
        for(int row=0;row<12;row++) {for(int col=0;col<12;col++) {b[row*12+col] = '#';}}
        for(int r=2;r<10;r++) {for(int c=2;c<10;c++) {b[r*12+c] = '.';}}
        
        int s = 0;
        int i = 0;
        int r = 0;
        int c = 0;
        char l;
        while(i<fen.length()) {
            l = fen.charAt(i);
            if (s==0) {
                if (l=='/') {
                    r++;
                    c=0;
                } else if ((l>='a')&&(l<='z')) {
                    b[(r+2)*12+c+2] = l;
                    c++;
                } else if ((l>='A')&&(l<='Z')) {     
                    b[(r+2)*12+c+2] = l;
                    c++;
                } else if ((l>='1')&&(l<='8')) {                
                    c = c + Integer.parseInt(""+l);
                } else {
                    s++;							
                }
            } else if (s==1) {
				if (l=='b') {
					t = -1;
				} else if (l=='w') {
					t = 1;
				} else {					
					s++;
				}				
            } else if (s==2) {
				if (l=='K') { 
					g += 1;
				} else if (l=='Q') {
					g += 2;
				} else if (l=='k') {
					g += 4;
				} else if (l=='q') {
					g += 8;
				} else {
					s++;				
				}				
            } else if (s==3) {
				
			}
            i++;
        }
        
    }
	
	public int getValue() {
		int value = 0;
		int stage = 0;
		SquaresLoop loop = new SquaresLoop(this);		
		while(loop.next()) {
			stage = 0;
			if (testSquare()) {
				stage =  Constants._VALUE[Constants.MAP[p]];
				stage += Constants.MAP[p+Constants.COLOR]*Constants.SQUARE_VALUE[s];
			}				
			value += stage;						
        }
		return value;
	}    
	
	public void dump() {
		getBoard().dump();	
		System.out.println("ep: "+e);
	}
	
	public String toString() {
		return getBoard().toString();
	}

}
